package generator

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"generator-tool/config"
	"generator-tool/internal/model"
)

type CodeGenerator struct {
	cfg            *config.GeneratorConfig
	inspector      *DBInspector
	templateLoader *TemplateLoader
}

type TemplateData struct {
	ProjectModule string            `json:"project_module"`
	PackageName   string            `json:"package_name"`
	StructName    string            `json:"struct_name"`
	TableName     string            `json:"table_name"`
	VarName       string            `json:"var_name"`
	PluralName    string            `json:"plural_name"`
	Fields        []model.FieldInfo `json:"fields"`
}

type TemplateTableData struct {
	ModelName  string
	VarName    string
	PluralName string
}

type RouterTemplateData struct {
	ProjectModule string                `json:"project_module"`
	Tables        []TemplateTableData   `json:"tables"`
	Database      config.DatabaseConfig `json:"database"`
}

type ExampleTemplateData struct {
	ProjectModule string `json:"project_module"`
}

type DatabaseTemplateData struct {
	ProjectModule string                `json:"project_module"`
	Database      config.DatabaseConfig `json:"database"`
}

func NewCodeGenerator(cfg *config.GeneratorConfig, templateDir string) (*CodeGenerator, error) {
	inspector, err := NewDBInspector(cfg)
	if err != nil {
		return nil, err
	}

	templateLoader, err := NewTemplateLoader(templateDir)
	if err != nil {
		inspector.Close()
		return nil, err
	}

	return &CodeGenerator{
		cfg:            cfg,
		inspector:      inspector,
		templateLoader: templateLoader,
	}, nil
}

// 辅助方法
func (g *CodeGenerator) shouldSkipTable(tableName string) bool {
	// 可以根据需要添加更多需要跳过的表
	skipTables := []string{
		"migrations",
		"migrations_lock",
		"schema_migrations",
		"gin_sessions", // Gin session 表
	}

	for _, skip := range skipTables {
		if strings.ToLower(tableName) == strings.ToLower(skip) {
			return true
		}
	}
	return false
}

func (g *CodeGenerator) toCamelCase(snake string) string {
	if snake == "" {
		return "Model"
	}

	// 处理复数形式，转换为单数
	singular := g.toSingular(snake)

	parts := strings.Split(singular, "_")
	for i := 0; i < len(parts); i++ {
		if len(parts[i]) > 0 {
			// 首字母大写
			parts[i] = strings.ToUpper(parts[i][:1]) + parts[i][1:]
		}
	}
	return strings.Join(parts, "")
}

func (g *CodeGenerator) toSingular(word string) string {
	// 简单规则：如果以s结尾且长度大于1，去掉s
	if len(word) > 1 && strings.HasSuffix(word, "s") {
		// 避免去掉一些本来就是单数但以s结尾的词
		exceptions := []string{"class", "status", "news", "species", "series"}
		for _, exception := range exceptions {
			if strings.HasSuffix(word, exception) {
				return word
			}
		}
		return word[:len(word)-1]
	}
	return word
}

// 生成数据库配置文件
func (g *CodeGenerator) generateDatabaseConfig() error {
	data := DatabaseTemplateData{
		ProjectModule: g.cfg.Generator.ProjectModule,
		Database:      g.cfg.Database,
	}

	return g.executeAndWriteTemplate("database.tpl", "config", "database.go", data)
}

// 生成路由文件
func (g *CodeGenerator) generateRouterFile(data RouterTemplateData) error {
	return g.executeAndWriteTemplate("router.tpl", "router", "routes.go", data)
}

// 生成使用示例
func (g *CodeGenerator) generateMainExample(data ExampleTemplateData) error {
	return g.executeAndWriteTemplate("main_example.tpl", "examples", "main_example.go", data)
}

// 生成 Model
func (g *CodeGenerator) generateModel(data TemplateData) error {
	return g.executeAndWriteTemplate("model.tpl", "models", data.StructName+".go", data)
}

// 生成 Repository
func (g *CodeGenerator) generateRepository(data TemplateData) error {
	filename := strings.ToLower(data.StructName) + "_repo.go"
	return g.executeAndWriteTemplate("repository.tpl", "repository", filename, data)
}

// 生成 Service
func (g *CodeGenerator) generateService(data TemplateData) error {
	filename := strings.ToLower(data.StructName) + "_service.go"
	return g.executeAndWriteTemplate("service.tpl", "service", filename, data)
}

// 生成 Controller
func (g *CodeGenerator) generateController(data TemplateData) error {
	filename := strings.ToLower(data.StructName) + "_controller.go"
	return g.executeAndWriteTemplate("controller.tpl", "controller", filename, data)
}

// 执行模板并写入文件
func (g *CodeGenerator) executeAndWriteTemplate(templateName, subDir, filename string, data interface{}) error {
	// 执行模板
	content, err := g.executeTemplate(templateName, data)
	if err != nil {
		return fmt.Errorf("执行模板 %s 失败: %v", templateName, err)
	}

	// 写入文件
	return g.writeFile(subDir, filename, content)
}

// 执行模板
func (g *CodeGenerator) executeTemplate(templateName string, data interface{}) (string, error) {
	tmpl := g.templateLoader.GetTemplate(templateName)
	if tmpl == nil {
		return "", fmt.Errorf("模板 %s 不存在", templateName)
	}

	var buf bytes.Buffer
	if err := tmpl.Execute(&buf, data); err != nil {
		return "", fmt.Errorf("执行模板失败: %v", err)
	}

	return buf.String(), nil
}

// 写入文件
func (g *CodeGenerator) writeFile(subDir, filename, content string) error {
	// 构建完整路径
	fullPath := filepath.Join(g.cfg.Generator.OutputBasePath, subDir)

	// 创建目录
	if err := os.MkdirAll(fullPath, 0755); err != nil {
		return fmt.Errorf("创建目录失败 %s: %v", fullPath, err)
	}

	// 文件路径
	filePath := filepath.Join(fullPath, filename)

	// 检查文件是否存在且不允许覆盖
	if !g.cfg.Generator.Overwrite {
		if _, err := os.Stat(filePath); err == nil {
			fmt.Printf("文件已存在，跳过: %s\n", filePath)
			return nil
		}
	}

	// 创建文件
	file, err := os.Create(filePath)
	if err != nil {
		return fmt.Errorf("创建文件失败 %s: %v", filePath, err)
	}
	defer file.Close()

	// 写入内容
	if _, err := file.WriteString(content); err != nil {
		return fmt.Errorf("写入文件失败 %s: %v", filePath, err)
	}

	fmt.Printf("生成文件: %s\n", filePath)
	return nil
}

func (g *CodeGenerator) Close() {
	if g.inspector != nil {
		g.inspector.Close()
	}
}

// toCamelCaseVariable 将结构体名转换为变量名（首字母小写）
func (g *CodeGenerator) toCamelCaseVariable(structName string) string {
	if len(structName) == 0 {
		return "model"
	}
	// 首字母小写，其余保持不变
	first := strings.ToLower(structName[:1])
	rest := structName[1:]
	return first + rest
}

func (g *CodeGenerator) GenerateAll() error {
	fmt.Println("开始生成代码...")

	var tablesToGenerate []config.TableConfig
	var templateTables []TemplateTableData

	// 处理需要生成的表
	if g.cfg.Generator.GenerateAll {
		// 获取数据库中所有表
		allTables, err := g.inspector.GetAllTables()
		if err != nil {
			return fmt.Errorf("获取所有表失败: %v", err)
		}

		for _, tableName := range allTables {
			if g.shouldSkipTable(tableName) {
				continue
			}

			// 为每个表创建配置并应用默认值
			tableConfig := config.TableConfig{
				Name: tableName,
			}
			tableConfig.ApplyDefaults()
			tablesToGenerate = append(tablesToGenerate, tableConfig)
		}
		fmt.Printf("发现 %d 个表，将自动生成代码\n", len(tablesToGenerate))
	} else {
		tablesToGenerate = g.cfg.Generator.Tables
		if len(tablesToGenerate) == 0 {
			fmt.Println("⚠️  未配置需要生成的表，也没有设置 generate_all: true")
			fmt.Println("💡 请在配置文件中设置 generate_all: true 或配置具体的表")
		} else {
			// 为每个配置的表应用默认值
			for i := range tablesToGenerate {
				tablesToGenerate[i].ApplyDefaults()
			}
		}
	}

	// 生成每个表的代码
	for _, tableCfg := range tablesToGenerate {
		fmt.Printf("处理表: %s (结构体: %s)\n", tableCfg.Name, tableCfg.ModelName)

		// 获取表信息
		tableInfo, err := g.inspector.GetTableInfo(tableCfg.Name)
		if err != nil {
			fmt.Printf("获取表信息失败 %s: %v\n", tableCfg.Name, err)
			continue
		}

		// 转换为字段信息
		fields := g.inspector.ConvertToFields(tableInfo.Columns)

		// 创建模板数据
		data := TemplateData{
			ProjectModule: g.cfg.Generator.ProjectModule,
			PackageName:   tableCfg.PackageName,
			StructName:    tableCfg.ModelName,
			TableName:     tableCfg.Name,
			VarName:       g.toCamelCaseVariable(tableCfg.Name),
			PluralName:    strings.ToLower(tableCfg.ModelName) + "s",
			Fields:        fields,
		}

		// 保存用于路由模板的数据（仅当需要生成路由时）
		if tableCfg.Generate.GetRouter() {
			templateTables = append(templateTables, TemplateTableData{
				ModelName:  tableCfg.ModelName,
				VarName:    data.VarName,
				PluralName: data.PluralName,
			})
		}

		// 生成各个组件（根据配置决定是否生成）
		if tableCfg.Generate.GetModel() {
			if err := g.generateModel(data); err != nil {
				fmt.Printf("生成Model失败 %s: %v\n", tableCfg.Name, err)
			}
		}

		if tableCfg.Generate.GetRepository() {
			if err := g.generateRepository(data); err != nil {
				fmt.Printf("生成Repository失败 %s: %v\n", tableCfg.Name, err)
			}
		}

		if tableCfg.Generate.GetService() {
			if err := g.generateService(data); err != nil {
				fmt.Printf("生成Service失败 %s: %v\n", tableCfg.Name, err)
			}
		}

		if tableCfg.Generate.GetController() {
			if err := g.generateController(data); err != nil {
				fmt.Printf("生成Controller失败 %s: %v\n", tableCfg.Name, err)
			}
		}
	}

	// 生成数据库配置文件
	if err := g.generateDatabaseConfig(); err != nil {
		fmt.Printf("生成数据库配置文件失败: %v\n", err)
	}

	// 生成路由文件（只有当有需要路由的表时才生成）
	if len(templateTables) > 0 {
		routerData := RouterTemplateData{
			ProjectModule: g.cfg.Generator.ProjectModule,
			Tables:        templateTables,
			Database:      g.cfg.Database,
		}
		if err := g.generateRouterFile(routerData); err != nil {
			fmt.Printf("生成路由文件失败: %v\n", err)
		}
	}

	// 生成使用示例文件
	exampleData := ExampleTemplateData{
		ProjectModule: g.cfg.Generator.ProjectModule,
	}
	if err := g.generateMainExample(exampleData); err != nil {
		fmt.Printf("生成使用示例失败: %v\n", err)
	}

	fmt.Println("🎉 代码生成完成！")
	return nil
}
